EJEMPLOS DE UTILIZACIN DE LAS LLAMADAS AL SISTEMA DEL SUBSISTEMA DE PROCESOS EN UNIX

/* PequeZa shell */

#include <stdio.h>
#include <string.h>

#define MAXARG 20
#define CIERTO 1
#define FALSO 0
#define PS1 "Orden :"

static void ejecuta (int argc, char *argv[]);
static int getargs (int *argcp, char *argv[], int max);

void main(void)
{  int argc;
char *argv [MAXARG+1];
while (CIERTO) {
  printf("%s",PS1);
  if (!getargs(&argc,argv,MAXARG) || argc==0)
	continue;  /*  Volver a leer una orden */
  ejecuta (argc,argv);   }
  printf("FIN DE EJECUCION \N");   }

static int getargs (int *argcp, char *argv[], int max)
{   static char cmd [100];
char *cmdp;
int i;
if (gets(cmd)==NULL)  return (FALSO);
cmdp=cmd;
for (i=0;i<=max;i++)
  {  if((argv[1]=strtok(cmdp, " \t"))==NULL)  break;
     cmdp=NULL;    }
  if (i>max)   {
       printf("Demasiados argumentos \n");
       return(FALSO);   }
  *argcp=i;
  return(CIERTO);  }

static void ejecuta (int argc, char *argv[])
{  execvp (argv[0], argc);
   printf("No puedo ejecutarlo \n");
}
	-----------------------------------
/* Ejemplo de fork() */
void main(void)
{
int pid;
printf("Empiezo un proceso \n");
pid=fork();
if(pid>0)   printf("Esto es el proceso PADRE : pid = %d \n",pid);
else        printf("Esto es el proceso HIJO  : pid = %d \n",pid);
return;
}
	-----------------------------------

/* Ejemplo de fork() */

#include <stdio.h>
#define ERROR -1

main(void)
{  int pid;
switch(fork())  {
  case ERROR: errorsistema ("fork");
	      return (1);
  case 0    : system ("ps -f");
	      printf("Fin del proceso HIJO \N");
	      exit(1);
  default   : if (wait(NULL)==ERROR)
		errorsistema("wait");
	      printf("Fin del proceso PADRE\n");  }
	      return 0;
}
	-----------------------------------
/* Ejemplo de una pequeZa shell utilizando fork() */

#include <stdio.h>
#include <string.h>

#define ERROR -1
#define MAXARG 20
#define CIERTO 1
#define FALSO 0
#define PS1 "Orden :"

static void ejecuta (int argc, char *argv[]);
static int getargs (int *argcp, char *argv[], int max);

void main(void)
{
int argc;
char *argv [MAXARG+1];
while (CIERTO) {
  printf("%s",PS1);
  if (!getargs(&argc,argv,MAXARG) || argc==0)
	continue;  /*  Volver a leer una orden */
  ejecuta (argc,argv);   }
  printf("FIN DE EJECUCION \N");
}

static int getargs (int *argcp, char *argv[], int max)
{
static char cmd [100];
char *cmdp;
int i;
if (gets(cmd)==NULL)  return (FALSO);
cmdp=cmd;
for (i=0;i<=max;i++)
  {  if((argv[1]=strtok(cmdp, " \t"))==NULL)  break;
     cmdp=NULL;    }
  if (i>max)   {
       printf("Demasiados argumentos \n");
       return(FALSO);   }
  *argcp=i;
  return(CIERTO);
}

static void ejecuta (int argc, char *argv[])
{
switch(fork())  {
  case ERROR: errorsistema ("fork");
	      return (1);
  case 0    : execvp (argv[0], argc);
              printf("No puedo ejecutarlo \n");
	      exit(1);
  default   : if (wait(NULL)==ERROR)
		errorsistema("wait");   }
return 0;
}
	----------------------------------
/* Ejemplo de exec() */

#include <stdio.h>
main()
{
execl ("/bin/echo", "echo", "Hola amigo\n", "esto", "es una lata",NULL);
return (0);
}
	-----------------------------------
/* El siguiente programa cuenta el ndmero de ficheros no directorios, creando un nuevo proceso por cada
fichero que encuentra en los directorios que va leyendo. Cada proceso hijo verifica el tipo de fichero,
si es un directorio comienza a generar hijos por cada entrada. Si el fichero no es directorio termina
devolviendo uno a su proceso padre. */
#include <stdio.h>
#include <sys/file.h>
#include <sys/dir.h>
#include <sys/stat.h>

main(int argc, char *argv[])
{
long count;
count=processFIle(argv[1]);
printf("Ndmero total de ficheros no directorios %ld\n",count);
return(0);
}

long processfile(char *name)
{
struct stat statbuf;
mode_t mode;
if(stat(name,&statbuf)==-1)return(0);
mode=statbuf.st_mode;
if (S_ISDIR(mode)) return(processDirectory(name));
else return(1);
}

long processDirectory(char *dirname)
{
int fd,children,i,charsRead,chilspid,status;
long count,totalcount;
char filename[100];
struct direct dirEntry;
fd=open(dirname,O_RDONLY);
children=0;
while(1)
  { charsRead=getdents (fd,&dirEntry,sizeof(struct direct));
  if(!charsRead) break;
  if(strcmp(dirEntry.d_name,".")&&strcmp(dirEntry.d_name,
"..");
     { if(!fork())
          { sprintf(filename,"%s/%s",dirname,dirEntry.d_name);
          count=processfile(filename);
          exit(count); }
     else ++children; }
  lseek(fd,dirEntry.d_off,SEEK_SET); }
close (fd);
totalCount=0;
for(i=0;i<=children;i++)
  { childPid=wait(&status);
  totalCount+=(status>>8); }
return(totalCount);
}
	---------------------------------------
/* Control del tiempo de ejecuci\n de un proceso hijo por parte del padre */

main(int argc, char * argv[])
{
int pid;
signal(SIGCHLD, childhandler);
pid=fork();
if (pid==0)
  { execvp(argv[2],&argv[2]);
  perror("limit"); }
else
  { sscanf(argv[1],"%d",&delay);
sllep(delay);
printf("El hijo %d excedi\ su lRmite y va a ser matado\n",pid);
kill(pid,SIGINT); }
}

childhandler (void)
{ int childpid, childstatus;
childpid=wait(&childstatus);
printf("El hijo %d termin\ en %d segundos\n",childpid,
delay);
exit(0);
}
	------------------------------------
/* Uso de las seZales SIGSTOP y SIGCONT para suspender y continuar un proceso. */
main()
{
int pid1,pid2;
pid1=fork();
if (pid1==0)
  { while(1)
     { printf("%d est< vivo\n",pid1);
     sleep(1); } }
pid2=fork();
if (pid2==0)
  { while(1)
     { printf("%d est< vivo\n",pid2);
     sleep(1); } }
sleep(3);
kill(pid1,SIGSTOP);
sleep(3);
kill(pid1,SIGCONT);
sleep(3);
kill(pid1,SIGINT);
kill(pid2,SIGINT);
}
	---------------------------------
/* at.c simulaci\n de la orden at de UNIX
versi\n para 4.3BSD
Recibe \rdenes para ejecutarlas en background a una hora
determinada. Uso: $at hh:mm:ss linea_de_\rdenes */
#include <stdio.h>
#include <time.h>
#include <signal.h>

#define SEGDIA 86400
#define hhmmss_ss (_hh,_mm,_ss) ((long)(_hh)*3600+ \
		(_mm)*60+(_ss))
#define ss_hhmmss (_seg,_hh,_mm,_ss) \
	 { _hh=(int)((_seg)/3600); \
	 _mm=(int)(((_seg)-(long)_hh*3600)/60); \
	 _ss=(int)((_seg)-(long)_hh*3600-_mm*60);  } 

void sigalarmhandler() {}

main(argc,argv)
int argc;
char **argv;
{ int hh,mm,ss,pid;
if (argc<3)
  { fprintf(stderr,"Uso: %s hh:mm:ss linea_de_\rdenes\n",argv[0]);
  exit(-1); }
if (sscanf(argv[1],"%d:%d:%d",&hh,&mm,&ss)!=3)
  { fprintf(stderr,"Formato de hora err\neo: %s\n",argv[1]);
  exit(-1); }
else if (hh<0||hh>23||mm<0||mm>59||ss<0||ss>59)
	{ fprintf(stderr,"Hora fuera de rango: %s\n",argv[1]);
	exit(-1); }
if ((pid=fork())==-1)
  { perror(argv[0]);
  exit(-1); }
else if (pid=0)
	{ long totalseg;
	time_t t;
	struct tm *tm;
	struct itimerval temporizador, temporizador_ant;
	temporizador.it_value.tv_usec=0;
	temporizador.it_interval.tv_sec=0;
	temporizador.it_interval.tv_usec=0;
	signal (SIGALRM,sigalarmhandler);
	time(&t);
	tm=localtime(&t);
	totalseg=hhmmss_ss(hh,mm,ss)-hhmmss_ss(tm->tm_hour,
			tm->tm_min,tm_>tm_sec);
	if (totalseg<0) totalseg+=SEGDIA;
	temporizador.it_value.tv_sec=totalseg;
	setitimer(ITIMER_REAL,&temporizador,&temporizador_ant);
	pause();   /* ejecutar cuando expire el temporizador */
	execvp(argv[2],&argv[2]);
	}
else exit(0); /*padre*/
}
	----------------------------------
/* Uso de alarm() */
#include <stdio.h>
#include <signal.h>
main(int argc, char *argv[])
{
int valor, tiempo, fact1,fact2,accion();
tiempo=atoi(argv[1]);
fact1=atoi(argv[2]);
fact2=atoi(argv[3]);
printf("Tiene Ud. %d segundos para resolver \n", tiempo);
printf("el producto de : %d por %d \n",fact1,fact2);
alarm(tiempo);
signal(SIGALRM,accion);
printf("Su solucion : ");
scanf("%d",&valor);
printf("Ha tardado Ud. %d segundos n",tiempo-alarm(0));
if (valor==fact1*fact2) printf("La respuesta es correcta !!!");
else printf("La respuesta es incorrecta !!!");
return (0);
}

int accion()
{ printf("\nSu tiempo se ha agotado. Lo siento !!!\n");
exit(0);
} 
	----------------------------------
/*
  DEFINICION ... Perfil de un proceso: a la hora de realizar una aplicacion nos puede interesar hacer estadisticas para conocer los tiempos de ejecucion de las diferentes funciones con que cuenta la aplicacion. La forma de realizar dicha estadistica, es creando un perfil.En UNIX los perfiles se crean mediante la llamada 'profil', cuya declaracion es la siguiente:
       void profil(buf,bufsiz,offset,scale)
       char *buf;
       int bufsiz,offset,scale;
   buf: apunta a un area de memoria cuya longitud viene dada por bufsiz
	Este programa muestra como crear un perfil de ejecucion de un proceso. Tiene tres funciones: f,g,fin. Mediante la llamada profil indicamos al sistema que haga un profiling de las tres funciones que nos interesen. */
#include <stdio.h>
#include <signal.h>
#define MAXF 1000
#define MAXG 5000

int main(),f(),g();
#define FINICIO ((int)main) /* inicio de la zona de c\digo a perfilar */
#define FFIN ((int)fin) /* final zona a perfilar */
/* Macros para acceder a los offset inicial y final de la funcion
   que se controla con el elemento x del array funciones */
#define inicio_funcion(x) ((funciones[(x)].inicio-FINICIO)/sizeof(int))
#define fin_funcion(x) ((funciones[(x)].fin-FINICIO)/sizeof(int))

struct funcion
{
  char *nombre;
  int inicio,fin;
  unsigned contador;
};
struct funciones[]
{
  "main",(int)main,(int)f-1,0,
  "f",(int)f,(int)g-1,0,
  "g",(int)g,(int)fin-1,0
};
#define total_funciones (sizeof(funciones)/sizeof(struct funcion))

main (int argc,char* argv[])
{
   bufsiz=FFIN-FINICIO;
   if ((buf=(int *)calloc(bufsiz,sizeof(int)))==null)
   {
     perror(argv[0]);
     exit(-1);
   }
   profil (buf,bufsiz,FINICIO,0xffff);
   signal(SIGALRM,fin);
   alarm(10);
   for(;;)
   {
    f();
    g();
   }
}

/* Funciones que simulan un tratamiento genJrico de informaci\n */
int f()
{
  long i=Irand48()%MAXF;
  while(i--);
}
int g()
{
  long i=Irand48()%MAXG;
  while(i--);
}

/* Esta funci\n analiza el buffer de perfiles para actualizar los
 contadores que hay en el array de funciones. Se activa cada 10 seg */

fin()
{
  int i,j;
  double total;
  static int cnt=0;
  for (i=0;i<bufsiz/sizeof(int);i++)
    if (buf[i])
      for (j=0;j<total_funciones;j++)
	if (i>=inicio_funcion(j) && i<=fin_funcion(j))
	   funciones[j].contador +=buf[i];
  total=0;
  for(i=0;i<total_funciones;i++)
    total +=funciones[i].contador;
  for (i=0;i<total_funciones;i++)
    printf("%s=%d=%g%%\n",funciones[i].nombre,funciones[i].contador,
	    funciones[i].contador/total*100);
  printf("\n");
  if(++cnt<5)
     signal(SIGALRM,fin);
  else
     exit(0);
     alarm(10);
}
	-----------------------------------------
/* CONTABILIDAD ... : cuando queremos llevar la contabilidad de los usuarios que utilizan el sistema (que ordenes utilizan, que tiempos emplean, etc. UNIX dispone de ordenes para habilitar o no la contabilidad, estas son 'accton' (habilita/deshabilita la contabilidad) y 'acctcom' (visualizar el contenido de un fichero de contabilidad)
       int acct(path)
       char *path;
   path: puntero al path name del fichero sobre el que se van a escribir los registros de contabilidad.
	Si path es NULL entonces la contabilidad se habilita, en caso contrario se deshabilita.
	Este programa lleva la contabilidad del sistema. Asocia bajo un mismo programa las \rdenes standard accton y acctcom.
   FORMA DE USO ... :   $capit82 [opciones] [fichero]
      -e: habilita la contabilidad
      -d: deshabilita la contabilidad
      -r: muestra por pantalla el contanido del fichero de contabilidad
      -f fichero: en el caso de que estJn presentes -e o -r, sirve para especificar un fichero diferente al de por defecto.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/acct.h>
#include <pwd.h>
#include <time.h>
#include <sys/param.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#define PERMISOS 0644

char opciones[]="derf:";
char error="[-der] [-f fichero]";
char *nombre_programa;

/* Analiza los par<metros de la lRnea de \rdenes */
main(int argc,char *argv[])
{
  int c;
  extern char *optarg;
  extern int optind;
  int errfig=0;
  char *home,acct_path[256];
  enum{NINGUNA,ACTIVAR,DESACTIVAR,LEER} accion=NINGUNA;
  FILE *f;
  struct acct act;
  struct passwd *pw,*getpwuid();
  struct tm *tm;
  time_t tfin;
  char *getenv(),*nombre_tty();
  nombre_programa=argv[0];
  while ((c=getopt(argc,argv,opciones)) !=EOF)
    switch(c)
      {
	case 'd':
	  accion=DESACTIVAR;
	  break;
	case 'e';
	  accion=ACTIVAR;
	  home=getenv("HOME");
	  sprintf(acct_path,"%s/adm/pacct",home);
	  break;
	case 'r':
	  accion=LEER;
	  home=getenv("HOME");
	  sprintf(acct_path,"%s/adm/pacct",home);
	  break;
	case 'f':
	  sprintf(acct_path,"%s",optarg);
	  break;
	case '?':
	  errflg++;
      }
  if (errflg)
    {
      fprintf(stderr,"forma de uso:%s%s\n",argv[0],error);
      exit(-1);
    }
  switch(accion)
    {
      case DESACTIVAR:
	       if (acct(NULL)==-1)
		 {
		   perror(argv[0]);
		   exit(-1);
		 }
	       else
		 {
		   printf("contabilidad desactivada");
		   exit(0);
		 }
      case ACTIVAR:
	     close(creat(acct_path,PERMISOS));
	     if(acct(acct_path)==-1)
	       {
		perror(acct_path);
		exit(-1);
	       }
	     else
	       {
		printf("contabilidad activada sobre %s\n",acct_path);
		exit(0);
	       }
      case LEER:
	    if ((f=fopen(acct_path,"r"))==NULL)
	      {
		perror(acct_path);
		exit(-1);
	      }
	    printf("%-9s%-8s%-8s%-8s%-8s%-5s%-8s\t%-5s\t%-5s\n","","","",
		   "HORA","HORA","CARACT","T.REAL","T.CPU");
printf("%-9s%-8s%-8s%-8s%-8s%-5s%-8s\t%-5s0t%-5s\n","ORDEN",
   "USUARIO","TTY","INICIO","FIN","L/E","L/E","(s.)","(s.)");
	    while (fread(&act,sizeof(act),1,f)==1)
	      {
		printf("%-c",(act.ac_flag&ASU)?'#':'');
		printf("%-8s",act.ac_comm);
		pw=getpwuid(act.ac_uid);
		printf("%-8s",pw->pw_pw_name);
		printf("-8s",nombre_tty(act.ac_tty));
		tm=localtime(&act.ac_btime);
     printf("%02d:%02d:%02d",tm->tm_hour,tm->tm_min,tm->tm_sec);
		tfin=act.ac_btime+act.ac_etime/HZ;
		tm=localtime(&tfin);
	printf("%02d:%02d:%02d",tm->tm_hour,tm->tm_min,tm->tm_sec);
		printf("%5d",act.ac_rw);
		printf("%8d\t",act.ac_io);
		printf("%2.2f\t",(float)act.ac_etime/HZ);
	printf("%2.2f\n",(float)(act.ac_utime+act.ac_stime)/HZ);
	      }
	    fclose(f);
	    exit(0);
      case NINGUNA:
	 fprintf(stderr,"Forma de uso: %s%s\n",argv[0],error);
	 exit(-1);
    }
}
/* A partir de un ndmero de dispositivo, devuelve un puntero a una cadena de caracteres, que contiene el nombre del fichero de dispositivo al que pertenece el ndmero. */
char *nombre_tty(dev)
dev_t dev;
{
  DIR *dir;
  struct dirent *dirent;
  char tty_path[256];
  static char n_tty[256];
  struct stat buf;
  if ((dir=opendir("/dev"))==NULL)
    {
      perror(nombre_programa);
      exit(-1);
    }
  seek(dir,2);
  while ((dirent=readdir(dir))!=NULL)
    {
       sprintf(tty_path,"/dev/%s",dirent->d_name);
       if(stat(tty_path,&buf)==-1)
	 {
	   perror(tty_path);
	   exit(-1);
	 }
       if(buf.st_rdev==dev)
	 {
	   sprintf(n_tty,"%s",dirent->d_name);
	   break;
	 }
    }
  closedir(dir);
  return(n_tty);
}
	---------------------------
/* DEPURACION DE PROGRAMAS
Un depurador es un programa que permite controlar la ejecuci\n de otro programa. UNIX suministra dos depuradores standard: adb y sdb.
      abd: depurador de bajo nivel que permite depurar programas
	   escritos en ensamblador.
      sdb: para programas escritos en C.
Ambos estan inplementados en base a la llamada 'ptrace'(llamada al sistema que permite la comunicaci\n entre dos procesos: el padre, que va a actuar como depurador, y el hijo, que va a actuar como proceso depurado)
	Este programa implementa el ndcleo de un depurador de bajo nivel. Las funciones que lleva a cabo son elementales:
   -Ejecutar paso a paso
   -Examinar una zona de memoria
   -Modificar una zona de memoria
 La forma de uso es la siguiente:
     $ capit83 [nom_programa]  */
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#define PT_SETTRC 0
#define PT_RDUSER 2
#define PT_WDUSER 5
#define PT_CONTIN 7
#define PT_EXIT 8
#define PT_SINGLE 9
char *ayuda[] =
  {
    "\n",
    "OPCIONES POSIBLES\n",
    "p direccion\t muestra el contenido de direccion \n",
    "s direccion valor\t escribe valor de direccion\n",
    "t[#]\t\t ejecuta # instrucciones maquina\n",
    "c\t\t continua la ejecucion del programa a depurar\n",
    "!orden\t\t ejecuta una orden del sistema operativo\n",
    "q\t\t salir del depurador\n",
    "?\t\t muestra el menu de ayuda\n",
    "\n"
  };
#define MAX_AYUDA (sizeof(ayuda)/sizeof(char *))
#define EQ(str1,str2) (strcmp((str1)(str2))==0)
main(int argc,char *argv[])
{
  int pid;
  char prog[256];
  if(argc<2)
    strcpy(prog,"a.out");
  else
    strcpy(prog,argv[1]);
  if((pid=fork())==0)
   {
     ptrace(PT_SETTRC);
     /* cargamos el codigo del programa a depurar */
     execcvp(prog,&argv[1],0);
     perror(prog);
     exit(127);
  }
/* proceso padre, se encarga de depurar */
 printf("proceso hijo: %d\n",pid);
 for(;;)
   {
     char str_ant[256],orden;
     int total,valor,direccion,i,estado;
     enum {NO,SI} repetir;
   /* esperamos a que el proceso hijo reciba la seZal SIGTRAP */
     wait(NULL);
     /* el proceso padre lee de la entrada standard una orden */
leer_orden:
     do
       {
	  printf("PID(%d)?==>ayuda<",getpid());
	  fflush(stdout);
	  gets(str_act);
	  if(EQ(str_act,""))
	    {
	      strcpy(str_act,str_ant);
	      repetir=SI;
	    }
	  else
	    {
	      strcpy(str_ant,str_act);
	      total=sscanf(str_act,"%c%x%x%x",&orden,&direccion,&valor);
	      repetir=NO;
	    }
       }while(total<=0);
     /* analisis de la orden introducida */
     switch(orden)
       case 'p':
	    if (repetir)
	      ++direccion;
	    else if(total!=2)
		   {
		     printf("[%s]incorrecto\n",str_act);
		     goto leer_orden;
		   }
	    if ((valor=ptrace(PT_RDUSER,pid,direccion))==-1)
	      printf("direccion 0x%xincorrecta\n",direccion);
	    else
	      printf("(0x%x)=0x%x=%d\n",direccion,valor,valor);
	    break;
       case 's':
	   if (total!=3)
	     {
		printf("[%s]incorrecto\n",str_act);
		goto leer_orden;
	     }
	   if (ptrace(PT_WDUSER,pid,direccion,valor)!=valor)
	     printf("direccion 0x%x incorrecta\n",direccion);
	   else
	      printf("(0x%x)=0x%x=%d\n",direccion,valor,valor);
	   break;
       case 't':
	   if (total==1)
	     valor=1;
	   else
	      valor=direccion;
	   for (i=0;i<valor;i++)
	     if(ptrace(PT_SINGLE,pid,1,0)==-1)
		perror(argv[0]);
	   break;
       case 'c':
	   if (ptrace(PT_CONTIN,pid,1,0)==-1)
	      perror(argv[0]);
	   break;
       case '!':
	 system(str_act+1);
	 goto leer_orden;
       case 'q':
	  if (kill(pid,0)==-1)
	    exit(0);
	  if (ptrace(PT_EXIT,pid)==-1)
	     perror(argv[0]);
	  exit(0);
       case '?':
	   for(valor=0;valor<MAX_AYUDA;valor++)
	     printf(ayuda[valor]);
	   goto leer_orden;
       default:
	   printf("%s incorrecto\n",str_act);
	   goto leer_orden;
     }
 }
}
	-------------------------------------
/* Con este programa vamos a mostrar el uso del depurador.
 Los puntos de parada son aquellos en los que el proceso recibe
 la seZal SIGTRAP. */

#include <signal.h>
int i;
main()
{
  int pid=getpid();
  printf("pid(%d)&i=0x%x\n",pid,(int)&i);
  printf("pid(%d)i=0x%x\n",pid,i);
  i=100;
  kill(getpid(),SIGTRAP);/* punto de parada */
  printf("pid(%d)i=0x%x\n",pid,i);
  kill(getpid(),SIGTRAP); /* punto de parada */
}
	------------------------------------
/* TUBERIAS SIN NOMBRE
	Este programa nos ayuda a ilustrar el envio de mensajes entre un proceso emisor y un proceso receptor a travJs de una tuberia sin nombre */

#include <stdio.h>
#define MAX 256
main()
{
   int tuberia[2];
   int pid;
   char mensaje[MAX];
   /* Creacion de la tuberia sin nombre */
   if (pipe(tuberia)==-1)
     {
	perror("pipe");
	exit(-1);
     }
   /* creacion del proceso hijo */
   if((pid=fork())==-1)
      {
	perror("fork");
	exit(-1);
      }
   else if(pid==0);
	 {
 /* El proceso receptor (hijo) se encarga de leer un mensaje
	   de la tuberia y presentarlo en pantalla */
	   while (read(tuberia[0],mensaje,MAX)>0 && strcmp(mensaje,"FIN") !=0)
	     printf("PROCESO RECEPTOR.MENSAJE:%s\n",mensaje);
	   close(tuberia[0]);
	   close(tuberia[1]);
	   exit(0);
	 }
       else
	 {
	   /* El proceso emisor (padre) se encarga de leer un mensaje de la entrada standard y escribirlo en la tuberia para que el proceso hijo lo reciba */
	   while(printf("PROCESO EMISOR.MENSAJE:")!=0 && gets(mensaje) !=NULL && write(tuberia[1],mensaje,strlen(mensaje)+1)>0
		 && strcmp(mensaje,"FIN")!=0)
	   close (tuberia[0]);
	   close (tuberia[1]);
	   exit(0);
	 }
}
	----------------------------------
/*  COMUNICACION BIDIRECCIONAL CON TUBERIAS SIN NOMBRE
Programa para ilustrar el envio de mensajes entre un proceso emisor y otro receptor a traves de dos tuberias sin nombre. El proceso emisor va a pedir un mensaje que le va a enviar al proceso receptor. Cuando el proceso receptor haya presentado el mensaje por pantalla, va a enviar al proceso emisor otro mensaje para indicarle que esta listo y que puede pedir otro mensaje al usuario */

#include <stdio.h>
#define MAX 256
main()
{
    int tuberia1[2],tuberia2[2];
    int pid;
    char mensaje[MAX];
    /* Creacion de las tuberias de comunicacion */
    if (pipe(tuberia1)==-1 || pipe(tuberia2)==-1)
      {
	perror("pipe");
	exit(-1);
      }
    /* creacion del proceso hijo */
    if((pid=fork())==-1)
      {
	perror("fork");
	exit(-1);
      }
    else if (pid==0)
      {
    /* El proceso hijo (receptor) se va a encargar de leer un
	    mensaje de la tuberia y presentarlo por pantalla. Al
	    recibir el mensaje FIN, el proceso termina */
	    while(read(tuberia1[0],mensaje,MAX)>0 && strcmp(mensaje,"FIN")!=0)
	      {
		printf("PROCESO RECEPTOR.MENSAJE:%s\n",mensaje);
		/* Le decimos al emisor que estamos listos para
		recibir otro mensaje */
		strcpy(mensaje,"LISTO");
		write(tuberia2[1],mensaje,strlen(mensaje)+1);
	      }
	    close(tuberia1[0]);
	    close(tuberia1[1]);
	    close(tuberia2[0]);
	    close(tuberia2[1]);
	    exit(0);
      }
      else
	{
   /* El proceso emisor (padre) se encarga de leer un mensaje
   de la entrada standard y escribirlo en la tuberia, para que
   el proceso hijo lo reciba. Al recibir FIN los dos procesos
   acaban */
	   while(printf("PROCESO EMISOR.MENSAJE:")!=0 && gets(mensaje) !=NULL && write(tuberia1[1],mensaje,strlen(mensaje)+1)>0
		 && strcmp(mensaje,"FIN")!=0)
	      do
		{
		  read(tuberia2[0],mensaje,MAX);
		}while(strcmp(mensaje,"LISTO")!=0);
	   close(tuberia1[0]);
	   close(tuberia1[1]);
	   close(tuberia2[0]);
	   close(tuberia2[1]);
	   exit(0);
	}
}
	-----------------------------
/* Este programa es un ejemplo para mostrar el uso que el shell
 hace de las tuberias.
 La forma de uso es la siguiente:
	   $ capit94 prog1 prog2
     que es equivalente a:
	   $ prog1 | prog2 */
#include <stdio.h>
main(int argc,char *argv[])
{
   int tuberia[2];
   int pid;
   if (argc<3)
     {
       fprintf(stderr,"Forma de uso:%s prog1 prog2\n",argv[0]);
       exit(-1);
     }
   if (pipe(tuberia)==-1)
     {
       perror(argv[0]);
       exit(-1);
     }
   if ((pid=fork())==-1)
     {
       perror(argv[0]);
       exit(-1);
     }
   else if (pid==0)
	  {
	    close(0);
	    dup (tuberia[0]);
	    close(tuberia[0]);
	    close(tuberia[1]);
	    standard de entrada */
	    execlp(argv[2],argv[2],0);
	  }
       else
	 {
	   close(1);
	   dup(tuberia[1]);
	   close(tuberia[0]);
	   close(tuberia[1]);
	   /* ejecucion de prog1 */
	   execlp(argv[1],argv[1],0);
	 }
       exit(0);
}
	--------------------------------
/* TUBERIAS CON NOMBRE (FIFO)
Este programa simula conversaciones por radio. Programa para llamar.
  La forma de uso es:
     $ capit94 usuario
  El programa exige que la variable de entorno LOGNAME este correctamente inicializada con el nombre de usuario */
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <utmp.h>
#define MAX 256
#define EQ(str1,str2) (strcmp(str1),(str2))==0)

int fifo12,fifo21;
char nom_fifo12[MAX],nom_fifo21[MAX];
char mensaje[256];

main(int argc,char *argv[])
{
   int tty;
   char terminal[MAX],*logname,*getenv();
   struct utmp *utmp,getutent();
   void fintransmision();
   if (argc !=2)
     {
       fprintf(stderr,"forma de uso: %s user\n",argv[0]);
       exit(-1);
     }
   while ((utmp=getutent())!=NULL && strncmp(utmp->ut_user,argv[1],8)!=0);
   if (utmp==NULL)
     {
       printf("EL USUARIO %s NO ESTA EN SESION\n",argv[1]);
       exit(0);
     }
   sprintf(terminal,"/dev/%s",utmp->ut_line);
   if ((tty=open(terminal,O_WRONLY))==-1)
     {
       perror(terminal);
       exit(-1);
     }
   logname=getenv("LOGNAME");
   sprintf(mensaje,"\n\tLLAMADA PROCEDENTE DEL USER %s\07\07\07\nRESPONDER ESCRIBIENDO:responder_a $s\n\n",logname,logname);
   write(tty,mensaje,strlen(mensaje)+1);
   close(tty);
   signal(SIGINT,fintransmision);
   sprintf(nom_fifo12,"/usr/tmp/%s_%s",logname,argv[1]);
   sprintf(nom_fifo21,"/usr/tmp/%s_%s",argv[1],logname);
   unlink(nom_fifo12);
   unlink(nom_fifo21);
   if (mknod(nom_fifo12,S_IFIFO | 0666,0)==-1 || mknod(nom_fifo21,S_IFIFO | 0666,0)==-1)
     {
       perror(argv[0]);
       exit(-1);
     }
   if ((fifo12=open(nom_fifo12,O_WRONLY))== -1 ||
	 (fifo21=open(nom_fifo21,O_RDONLY))==-1)
      {
       perror(argv[0]);
       exit(-1);
      }
   printf("LLAMADA ATENDIDA\07\07\07\n");
   do
     {
       printf("<==");
       gets(mensaje);
       write(fifo12,mensaje,strlen(mensaje)+1);
       if (EQ(mensaje,"cambio"))
	 do
	   {
	     read(fifo21,mensaje,MAX);
	     printf("==> %s\n",mensaje);
	   }while(!EQ(mensaje,"cambio"));
     }while(!EQ(mensaje,"cambio"));
     /*FIN DE LA TRANSMISION*/
     printf(FIN DE TRANSMISION");
     close(fifo12);
     close(fifo21);
     exit(0);
}

void fintransmision(int sig)
{
  sprintf(mensaje,"corto");
  write(fifo12,mensaje,strlen(mensaje)+1);
  printf("fin de transmision");
  close(fifo12);
  close(fifo21);
  exit(0);
}
	--------------------------------
/* Programa de simulacion de conversaciones por radio. Programa para responder.
  Forma de uso:
		$ capit95 usuario
  Este programa exige que la variable de entorno LOGNAME este bien inicializada con el nombre de usuario */

#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAX 256
#define EQ(str1,str2) (strcmp((str1),(str2))==0)

int fifo12,fifo21;
char nom_fifo12[MAX],nom_fifo21[MAX],mensaje[MAX];
main(int argc,char *argv[])
{
   char *logname,*detenv();
   void fintransmision();

   if (argc!=2)
     {
       fprintf(stderr,"forma de uso:%s user\n",argv[0]);
       exit(-1);
     }
   logname=getenv("LOGNAME");
   signal(SIGINT,fintransmision);
   sprintf(nom_fifo12,"/usr/tmp/%s_%s",argv[1],logname);
   sprintf(nom_fifo21,"/usr/tmp/%s_%s",logname,argv[1]);
   if ((fifo12=open(nom_fifo12,O_WRONLY))==-1) ||
	(fifo21=open(nom_fifo21,O_WRONLY))==-1)
     {
       perror(nom_fifo21);
       exit(-1);
     }
   do
     {
       printf("==>");fflush(stdout);
       read(fifo12,mensaje,MAX);
       printf("%s\n",mensaje);
       if (EQ(mensaje,"cambio"))
	 do
	   {
	      printf("<==");
	      gets(mensaje);
	      write(fifo21,mensaje,strlen(mensaje)+1);
	   }while ()!EQ(mensaje,"cambio"));
     }while (!EQ(mensaje,("corto"));
     printf("FIN TRANSMISION");
     close(fifo12);
     close(fifo21);
     exit(0);
}

void fintransmision(sig)
{
  sprintf(mensaje,"corto");
  write(fifo21,mensaje,strlen(mensaje)+1);
  printf("FIN TRANSMISION");
  close(fifo12);
  close(fifo21);
  exit(0);
}
	-------------------------------
/* Empleo del polling o interrogaci\n peri\dica
Este programa emula comunicaciones telefonicas. Vamos a manejar dos fuentes de datos, el teclado y una tuberia de comunicaciones. Como la comunicacion es bidireccional, necesitamos dos tuberias. Basicamente el programa lee datos del teclado y escribe en una de las tuberias, o lee datos de la segunda tuberia y los escribe en la pantalla. La periodicidad con la que preguntaremos la existencia de datos de entrada sera de 1 segundo. Primero preguntaremos por el teclado y luego por la tuberia.
   Forma de uso:
       $ capit96 -e usuario --> hacemos una llamada
       $ caipt96 -r usuario --> contestamos a una llamada */

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <utmp.h>
#define MAX 256
#define EQ(str1,str2) (strcmp((str1,str2))==0)

int fifo_12,fifo_21;
char nombre_fifo_12[MAX],nombre_fifo_21[MAX];
char mensaje[MAX];
int estado;

main (argc,argv)
int argc;
char*argv[];
{
  int tty;
  enum{LLAMAR,RECIBIR} tipo_llamada;
  char terminal [MAX],*cadena,*lognamr,*getenv(),*leer_cadena();
  struct utmp *utmp,*getutent();
  void fin_de_transmisi\n();

  if(argc !=3 || (!EQ(argv[1],"-e") && !EQ(argv[1],"-r")))
  {
     fprinff(stderr,"Forma de uso: %s-el-r usuario\n*,argv[0]);
     exit(-1);
  }
  else if(EQ(argv[1],"-e"))
     tipo_llamada=LLAMAR;
  else
     tipo_llamada=RECIBIR;
  while((utmp=getutent())!=NULL&&
     strncmp(utmp->ut_user,argv[2],8 !=0);
  if(utmp==NULL)
  {
     prinff("EL USUARIO %s NO ESTA EN SESION.\n",argv[2]);
     exit(0);
  }
  logname=getenv("LOGNAME");
  sprinff(nombre_fifo_12,"/usr/tmp/%s_%s",logname,argv[2]);
  sprinff(nombre-fifo-21,"/usr/tmp/%s_%s",argv[2],logname);
  if(tipo_llamada==LLAMAR)
  {
     sprinff(terminal,"/dev/%s",utmp->ut_line);
     if((tty=open(terminal,O_WRONLY))==-1)
     {
	perror(terminal);
	exit(-1);
     }
     sprinff(mensaje,"\n\tLLAMADA PROCEDENTE DEL USUARIO %s\07\n\
     RESPONDER ESCRIBIENDO:llamar -r %s\n\n",logname,logname);
     write(tty,mensaje,strlen(mensaje)+1);
     close(tty);
     unlink(nombre_fifo_12);
     unlink(nombre_fifo_21);
     if(mknod(nombre_fifo_12,S_IFIFO | 0666,0)==-1||
	mknod(nombre_fifo_21,S_IFIFO | 0666,0)==-1)
     {
	perror(argv[0]);
	exit(-1);
     }
  }
  if((fifo_21=open(nombre_fifo_21,O_RDONLYIO_NDELAY))==-1 ||
     (fifo_12=open(nombre_fifo_12,O_WRONLY))==-1)
  {
     if(fifo_12==-1) perror(nombre_fifo_12);
     else perror(nombre_fifo_21);
     exit(-1);
  }
  if(tipo_llamada==LLAMAR) prinff("LLAMADA ATENDIDA.\07\n");
  estado=fcntl(0,F_GETFL,0);
  if(fcntl(0,F_SETFL,estado | O-NDELAY)==-1) perror("fcntl");
  signal(SIGINT,fin_de_transmisi\n);
  prinff("<=="),fflush(stdout);
  do
  {
    if((cadena=leer_cadena())!=NULL)
      {
	 if(cadena[0]!=0)
	   { strcpy(mensaje,cadena);
	   write(fifo_12,mensaje,strlen(cadena)+1);}
      prinff("<=="),fflush(stdout);
      }
      if(read(fifo_21,mensaje,MAX)>0)
        {	prinff("==>%s\n",mensaje);
	   prinff("<=="),fflush(stdout); }
     sleep(1);
  }while(!EQ(mensaje,"corto"));
  fin_de_transmisi\n();
}

void fin_de_transmisi\n(sig)
int sig;
{
   fcntl(0,F_SETFL,estado);
   sprinff(mensaje,"corto");
   write(fifo_12,mensaje,strlen(mensaje)+1);
   prinff("FIN DE TRANSMISI[N.\n");
   close(fifo_12);
   close(fifo_21);
   fflush(stdin);
   exit(0);
}

char *leer_cadena()
{
   #define CR 10
   static char cadena[MAX];
   char cadena_aux[MAX];
   static int primera_vez=1;
   int nbytes,i;
   if(primera_vez)
   {
      cadena[0]=0;
      --primera_vez;
   }
   if((nbytes=read(0,cadena_aux,MAX))==0)
       return(NULL);
   for(i=0;i<nbytes;i++)
      if(cadena_aux[i]==CR)
      {
	 cadena_aux[i]=0;
	 strcat(cadena,cadena_aux);
	 ++primera_vez;
	    return(cadena);
      }
   cadena_aux[i]=0;
   strcat(cadena,cadena_aux);
   return(NULL);
}
	----------------------------------------
/* Este programa sincroniza dos procesos para que se vayan ejecutando de forma alternativa por medio de dos sem<foros por lo menos. Uno de los sem<foros lo usa el padre para darle paso al hijo, y el otro lo utiliza el hijo para darle paso al padre. */

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define SEM_HIJO 0
#define SEM_PADRE 1

main(argc,argv)
int argc;
char*argv[];
{
   int i=10,semid,pid;
   struct sembuf operacion;
   key_llave;
   llave=ftok(argv[0],'k');
   if((semid=semget(llave,2,IPC_CREAT | 0600))==-1)
   {
      perror("semget");
      exit(-1);
   }
   semctl(semid,SEM_HIJO,SETVAL,09;
   semctl(semid,SEM_PADRE,SETVAL,1);
   if((pid=fork())==-1)
   {
      perror("fork");
      exit(-1);
   }
   else if(pid==0)
   {
      while(i)
      {
	 operacion.sem_num=SEM_HIJO;
	 operacion.sem_op=1;
	 operacion_flg=0;
	 semop(semid,&operacion,1);
	 printf("PROCESO HIJO:%d\n",i--);
	 operacion.sem_num=SEM_PADRE;
	 operacion.sem_op=1;
	 semop(semid,&operacion,1);
      }
      semctl(semid,0,IPC_RMID,0);
   }
   else
   {
      operacion.sem_flg=0;
      while(i)
      {
	 operacion.sem_num=SEM_PADRE;
	 operacion.sem_op=-1;
	 semop(semid,&operacion,1);
	 printf("PROCESO PADRE:%d\n",i--);
	 operacion.sem_num=SEM_HIJO;
	 operacion.sem_op=1;
	 semop(semid,&operacion,1);
      }
      semctl(semid,0,IPC_RMID,0);
   }
}
	-------------------------------
/*  MEMORIA COMPARTIDA
Este programa resuelve un algoritmo para multiplicar matrices. El programa principal se encarga de leer dos matrices y comprueba si se pueden multiplicar. Posteriormente arrancaran todos los procesos. Cada proceso se va a ocupar de generar una fila de la matriz producto mientras queden filas por generar. Para controlar la fila que debe generar cada proceso utilizamos un sem<foro que se inicializa con el total de filas de la matriz producto y se va decrementando por cada fila generada. El principal se queda esperando a que los dem<s terminen para dar el resultado. */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

typedef struct
{
   int shmid;
   int filas,columnas;
   float **coef;
}matriz;

matriz *crear_matriz(filas,columnas)
int filas,columnas;
{
   int shmid,i;
   matriz *m;
   shmid=shmget(IPC_PRIVATE, sizeof(matriz)+filas* sizeof(float*) + filas*columnas*sizeof(float), IPC_CREAT | 0600);
   if(shmid==-1)
   {
      perror("crear_matriz(shmdt)");
      exit(-1);
   }
   if((m=(matriz*)shmat(shmid,0,0))==(matriz*)-1)
   {
      perror("crear_matriz(shmdt)");
      exit(-1);
   }
   m->shmid=shmid;
   m->filas=filas;
   m->columnas=columnas;
   m->coef=(float**)&m->coef+sizeof(float**);
   for(i=0;i<filas;i++)
     m->coef[i]=(float*)&m->coef[filas]+i*columnas*sizeof(float);
     return m;
}

matriz *leer_matriz()
{
  int filas,columnas,i,j;
  matriz * m;

  printf("Filas:");
  scanf("%d",&filas);
  printf("Columnas:");
  scanf("%d",&columnas);
  m=crear_matriz(filas,columnas);
  for(i=0;i<filas;i++)
   for(j=0;j<columnas;j++)
	canf("%f",&m->coef[i][j]);
  return m;
}

matriz *multiplicar_matrices(a,b,numproc)
matriz*a,*b;
int numproc;
{
  int p,semid,estado,i,j,k;;
  matriz *c;

  if(a->columnas!=b->filas) return NULL;
  c=crear_matriz(a->filas,b->columnas);
  semid=semget(IPC_PRIVATE,2,IPC_CREAT | 0600);
  if(semid==-1)
    {
    perror("multiplicar_matrices(semget)");
    exit(-1);
    }
  semctl(semid,0,SETVAL,1);
  semctl(semid,1,SETVAL,c->filas+1);
  for(p=0;p<numproc;p++)
    {
    if(fork()==0)
	 {

	 struct sembuf operacion;
      operacion.sem_flg=SEM_UNDO;
	 while(1)
	   {
	   operacion.sem_num=0;
	   operacion.sem_op=-1;
	   semop(semid,&operacion,1);
	   i=semctl(semid,1,GETVAL,0);
	   if(i>0)
	    {
	    semctl(semid,1,SETVAL,--i);
	    operacion.sem_num=0;
	    operacion.sem_op=1;
	    semop(semid,&operacion,1);
	    }
	   else exit(0);
	   for(j=0;j<c->columnas;j++)
	    {
	    c->coef[i][j]=0;
	    for(k=0;k<a->columnas;k++)
	    c->coef[i][j]+=a->coef[i][k]*b->coef[k][j];
	    }  }  }
      }
  for(p=0;p<numproc;p++)
  wait(&estado);
  semctl(semid,0,IPC_RMID,0);
  return c;
}

destruir_matriz(m)
matriz *m;
{
shmctl(m->shmid,IPC_RMID,0);
}

imprimir_matriz(m)
matriz *m;
{
 int i,j;
 for(i=0;i<m->filas;i++)
  {
  for(j=0;j<m->columnas;j++)
    printf("%g",m->coef[i][j]);
  printf("\n"); }
}

main(argc,argv)
int argc;
char *argv[];
{
  int numproc;
  matriz *a,*b,*c;

if(argc!=2) numproc=2;
else numproc=atoi(argv[1])+1;
a=leer_matriz();
b=leer_matriz();
c=multiplicar_matrices(a,b,numproc);
if(c!=NULL) imprimir_matriz(c);
else fprintf(stderr,"Las matrices no se pueden multiplicar.");
destruir_matriz(a);
destruir_matriz(b);
destruir_matriz(c);
}
	-------------------------------------
/* censo.h
El fichero de cabecera para los clientes y el siguiente programa gestor de una base de datos centralizada */
#ifndef _CENSO_
#define _CENSO_

struct persona{
   char nombre[61];
   char direccion[121];
   char telefono[11];
};

struct mensaje{
   long pid;
   int orden;
   union
   { struct persona persona;
   } datos;
};

#define LONGITUD (sizeof(struct mensaje)-sizeof(long))
#define LISTAR 1
#define ANNADIR 2
#define FIN 3
#define ERROR 4

#define FICHERO_LLAVE "censo.h"
#define CLAVE_CLIENTE_GESTOR 'K'
#define CLAVE_GESTOR_CLIENTE 'L'

#endif
	---------------------------
/* Este programa se va a comportar como un gestor de la BD de
 personas. Cada registro consta de:
	      Nombre:
	      Direccion:
	      Tlf:
Para comunicar este programa con el cliente usaremos una cola de mensajes. El tipo de cada cola coincide con el PID del proceso cliente. Cuando varios clientes soliciten servicio del gestor se podra identificar a que proceso pertenece cada mensaje. Los mensajes que vayan desde el gestor hacia el cliente se envian a travJs de otra cola. */
/* Programa Gestor de la Base de Datos */

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "censo.h"

main(argc,argv)
int argc;
char *argv[];
{
   int cola_cg,cola_gc;
   struct mensaje mensaje;
   key_t llave;
   FILE*pf;

   if(argc!=2)
   {
      fprintf(stderr,"Forma de uso:%s fichero.\n",argv[0]);
      exit(-1);
   }
   llave=ftok(FICHERO_LLAVE,CLAVE_CLIENTE-GESTOR);
   if((cola_cg=msgget(llave,IPC_CREAT | 0666))==-1)
   {
      perror("msget");
      exit(-1);
   }
   llave=ftok(FICHERO_LLAVE,CLAVE_GESTOR_CLIENTE);
   if(cola_gc=msgget(llave,IPC_CREAT | 0666))==-1)
   {
      perror("msget");
      exit(-1);
   }
   while(1)
   {
      msgrcv(cola_cg,&mensaje,LONGITUD,0,0);
      switch(mensaje.orden)
      {
	 case LISTAR:
	    if((pf=fopen(argv[1],"r"))==NULL)
	    {
	       mensaje.orden=ERROR;
	       msgsnd(cola_gc,&mensaje,LONGITUD,0);
	       break;
	    }
	    while(fread(&mensaje.datos.persona,sizeof(struct
	       persona),1,pf)==1)
	       msgsnd(cola_gc,&mensaje;LONGITUD,0);
	    fclose(pf);
	    mensaje.orden=FIN;
	    msgsnd(cola_gc,&mensaje;LONGITUD,0);
	    break;
	 case ANNADIR:
	    if((pf=fopen(argv[1],"a"))==NULL)
	    {
	       mensaje.orden=ERROR;
	       msgsnd(cola_gc,&mensaje,LONGITUD,0);
	       break;
	    }
	    fwrite(&mensaje.datos.persona,sizeof(struct persona),1,pf);
	    fclose(pf)
	    mensaje.orden=FIN;
	    msgsnd(cola_gc,&mensaje,LONGITUD,0);
	    break;
	 case FIN:
	    msgctl(cola_cg,IPC_RMID);
	    msgctl(cola_gc,IPC_RMID);
	    pritf("Programa gestor parado a petici\n de un cliente.\n");
	    exit(0);
	 default:
	    mensaje.orden=ERROR;
	    msgsnd(cola_gc,&mensaje;LONGITUD,0):
      }
   }
}
	------------------------------------
/*  Cliente de la BD. Puede realizar dos tipos de operaciones:
	     - Visualizar el contenido de la BD
	     - AZadir nuevos registros  */

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "censo.h"

main(argc,argv)
int argc;
char*argv[];
{
   int cola_cg,cola_gc,pid;
   char opci\n;
   struct mensaje mensaje;
   key_t llave;
   enum {NO,SI} recibir=NO;

   llave=ftok(FICHERO_LLAVE,CLAVE_CLIENTE_GESTOR);
   if((cola_cg=msgget(llave,0666))==-1)
   {
      perror("msget");
      exit(-1);
   }
   llave=ftok(FICHERO_LLAVE,CLAVE_GESTOR_CLIENTE);
   if((cola_gc=msgget(llave,0666))==-1)
   {
      perror("msget");
      exit(-1);
   }
   mensaje.pid=pid=getpid();
   while(1)
   {
      printf("Orden:");
      fflush(stdout);
      opcion=getchar();
      fflush(stdin);
      switch(opcion)
      {
	 case '|':
	    recibir=SI;
	    mensaje.orden=LISTAR;
	    msgsnd(cola_cg,&mensaje,LONGITUD,0);
	    break;
	 case 'a':
	    recibir=SI;
	    printf("\tNombre:");
	    gets(mensaje.datos.persona.nombre);
	    printf("\tDirecci\n:");
	    gets(mensaje.datos.persona.direccion);
	    printf("\tTelefono:");
	    gets(mensaje.datos.persona.telefono);
	    mensaje.orden=ANNADIR;
	    msgsnd(cola_cg,&mensaje,LONGITUD,0);
	    break;
	 case 'f':
	    recibir=NO;
	    mensaje.orden=FIN;
	    msgsnd(cola_cg,&mensaje,LONGITUD,0);
	    break;
	 case 's':
	    exit(0);
	 default:
	    recibir=NO;
	    printf("Opci\n[%c]err\nea.\n",opcion);
	    printf("Opciones disponibles:\n");
	    printf("\ta-aZadir registros.\n");
	    printf("\tf-para el programa gestor.\n");
	    printf("\tl-visualizar todos los registros.\n");
	    printf("\ts-para el programa cliente.\n");
      }
      if(recibir==SI)
	 do
	 {
	    msgrcv(cola_gc,&mensaje,LONGITUD,pid,0);
	    switch(mensaje.orden)
	    {
	       case FIN:
		  break;
	       case LISTAR:
	printf("\n\tNombre:%s\n",mensaje.datos.persona.nombre);
	printf("\tDirecci\n:%s\n",mensaje.datos.persona.direccion);
	printf("\tTelJfono:%s\n",mensaje.datos.persona.telefono);
		  break;
	       case ERROR:
		  printf("Mensaje de error recibido.\n");
		  break;
	       default:
		  printf("Tipo de mensaje desconocido[%d]\n",
		     mensaje.orden);
	    }
	 }while(mensaje.orden!=FIN && mensaje.orden!=ERROR);
   }
}
	--------------------------------------
/* cat f1 f2 f3 | pr | wc -lc */
# include <stdio.h>

main()
{
int p[2];
int n,q;
   
if (pipe(p) == -1)
  { fprintf(stderr, "error primer pipe \n");
    exit(1); }
if ((n = fork()) == -1 )
  { fprintf (stderr, "error de fork \n");
    exit(2); }
if (!n)
  {
  close(1);
  dup(p[1]);
  close(p[1]);
  close(p[0]);
  execlp ("cat","cat","f1","f2","f3",NULL);
  fprintf ("error de exec cat \n");
  exit(3);
  }
close (p[1]);
q = p[0];
if (pipe(p) == -1 )
 { fprintf (stderr, "error del segundo pipe \n");
   exit(4); }
if ((n=fork()) == -1) 
 { fprintf (stderr, "error del fork \n");
   exit(5); }
if(!n)
 { close(0);
   dup(q);
   close(q);
   close(1);
   dup (p[1]);
   close(p[1]);
   close(p[0]);
   execlp ("pr","pr",NULL);
   exit(6);  }
close(q);
close(p[1]);
close(0);
dup(p[0]);
close(p[0]);
execlp ("wc","wc","-lc",NULL);
fprintf(stderr, "error de exec wc \n");
}   
	--------------------------------
/* Uso de getpid(),getppid(),getpgrp(),getuid(),geteuid() */
#include <stdio.h>
main(argc, argv)
int argc;
char *argv[];
{
int rc=0, estado;

if (argc!=1) {
  fprintf(stderr,"uso: fork1\n");
  rc=1;
} else  if (fork()) {
    wait (&estado);
    printf ("PADRE  pid=%8d   ppid=%8d  id-grupo=%8d ur=%8d  ue=%8d\n",getpid(),getppid(),getpgrp(),getuid(),geteuid());
    printf ("El codigo de retorno del hijo es: %d\n",estado);
   } else
      printf ("HIJO   pid=%8d   ppid=%8d  id-grupo=%8d ur=%8d  ue=%8d\n",getpid(),getppid(),getpgrp(),getuid(),geteuid());
exit (rc);
}
	-----------------------------
/* Uso de pipe() */
#include <stdio.h>
#include <fcntl.h>

main(argc, argv, envp)
int argc;
char *argv[];
char *envp;
{
int p[2],d1,d2,n;
char ch[10];
   pipe(p);
   d1=open("f",O_RDWR|O_CREAT|O_TRUNC,0666);
   if (fork()!=0) {
      sleep(1);
      printf ("Lanzamiento del proceso 1\n");
      d2=open("f",O_RDWR,0);
      write (p[1],"abcde",5);
      sleep(5);
      write (p[1],"fghij",5);
      n=read (p[0],ch,10);
      printf ("Proceso 1: n=%d\n",n);
      write (d2,ch,n);
      sleep(5);
      read (d1,ch,2);
      printf ("Proceso 1: %c %c\n",ch[0],ch[1]);
      write (d1,"AB",2);
      sleep(5);
      read (d2,ch,1);
      printf ("Proceso 1: %c\n",ch[0]);
      read (d1,ch,1);
      printf ("Proceso 1: %c\n",ch[0]);
      _exit(0);
   }else{
      printf ("Lanzamiento del proceso 2\n");
      d2=open("f",O_RDWR,0);
      sleep(2);
      n=read (p[0],ch,10);
      printf ("Proceso 2: n=%d\n",n);
      write (d2,ch,n);
      sleep(5);
      read (d1,ch,2);
      printf ("Proceso 2: %c %c\n",ch[0],ch[1]);
      sleep(5);
      write (d2,"01",2);
      _exit(0);
   }
}
	------------------------------
/* Uso de signal () */
#include <stdio.h>

main(argc, argv)
int argc;
char *argv[];
{
int child;

if (argc!=1) {
  fprintf(stderr,"uso: fork5\n");
  exit(1);
} else  if ((child=fork())==0) {
    printf ("HIJO pid=%8d ppid=%8d\n",getpid(),getppid());
    signal(SIGINT,catcher)
    pause(); }
printf ("PADRE pid=%8d ppid=%8d\n",getpid(),getppid());
printf ("HIJO  pid=%8d ppid=%8d\n",child,getppid());
exit (child);
}

int catcher(signo)
int signo;
{
printf ("Hola soy yo de nuevo.\n");
printf ("Atrapada la seZal ndmero %d\n",signo);
fflush (stdout);
}
	----------------------------------
/* Uso de getxxid () */
#include  "/usr/include/string.h" 
#include "/usr/include/stdio.h"

main(argc, argv, envp)
int argc;
char *argv[];
char *envp[];
{
int ret;
 
if (!strcmp(argv[1],"-p") || !strcmp(argv[1],"-P"))
  {
  printf("mi ID de proceso primario : %d\n",getppid());
  printf("mi ID de grupo es         : %d\n",getpgrp());
  }
else if (!strcmp(argv[1],"-g") || !strcmp(argv[1],"-G"))
  {
  printf ("mi ID de grupos real de procesos es: %d\n", getgid());
  printf ("mi ID de grupo efectivo de procesos es: %d\n", getegid());
  }
else if (!strcmp(argv[1],"-u") || !strcmp(argv[1],"-U"))
  {
  printf ("Mi ID de usuario real es     : %d\n", getuid());
  printf ("Mi ID de usuario efectivo es : %d\n", geteuid()); 
  }
else 
 printf(" %s ES UNA OPCION INVALIDA ... PRUEBA DE NUEVO\n Opciones: -p -g -u\n",argv[1]);
}
	-----------------------------
/* ejemplo de llamadas al sistema: msgctl, msgsnd, msgrcv */

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define DIM 100

char txt[] ="Mensaje";
struct mansae {
	int msg_id;
	char texto[DIM] ;}  mensaje;

main()
{
int i,key,ppid,estatus;
struct mansae *pmensaje;
struct msgqid_ds *buf;
pmensaje=&mensaje;

if ((key=msgget(IPC_PRIVATE,IPC_CREAT|0666)) ==-1)
	errorSistema("msgget");
system("ipcs -q");
sleep(2);
if ((ppid=getpid())==-1)
  errorSistema("getpid");
switch(fork())
  { case -1: errorSistema("fork");
    case 0: sleep(1);
		  if(msgrcv(key,mensaje,DIM,ppid,IPC_NOWAIT)==-1)
				errorSistema("msgrcv");
		  printf("Mensaje del Hijo\nHe recibido:%s n",pmensaje-texto);
		  exit(0);
   default: sprintf(pmensaje->texto,"%s \n",txt);
		  pmensaje->msg_id=ppid;
		  if(msgsnd(key,pmensaje,DIM,IPC_NOWAIT)==-1)
				errorSistema("msgsnd");
		  i=wait(&estatus);
		  msgctl(key,IPC_RMID,buf);
		  system("ipcs -q");
		  sleep(1);
		  printf("Mensaje del Padre: Continuo \n");  
		  return(0); }
}
	---------------------------
/* Ejemplo de llamadas al sistema: shmget, shmat, shmdt*/

#include <stdio.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define SHMKEY 0X100

char *region;
int shmid;

main()
{
int i, id_hijo;
char miregion[10],*rp;
char *shmat();

if ((shmid=shmget((key_t)(SHMKEY),256,IPC_CREAT|0664))>0)
{  if((shmid=shmget((key_t)(SHMKEY),0,IPC_EXCL|0664))>0)
	{ perror("shmget"); exit(1);  } }

switch(fork())
  { case -1: perror("fork"); return (2);
    case 0: signal(SIGUSR1,enmarcha);
	  signal(SIGUSR2,termina);
	  pause();
	  if((region=shmat(shmid,region,SHM_RND|0664))<(char *)0)
		{ perror("Hijo:shmat"); return(3);  }
	  strncpy(miregion,region,10);
	  for(;;)
	  {  for(i=0;i<10;i++)
	     { if(region[i]!=miregion[i])
		{ printf("\n\n OJO hay CAMBIOS !!!\n");
		printf(" DE: %s \n",miregion);
		printf("  A: %s \n",region);
		strncpy(miregion,region,10); }  } }
  default: break;
  }
if((region=shmat(shmid,region,SHM_RND|0664))<(char *)0)
	{ perror("Padre:shmat"); return(3);  }
for(i=0;i<10;i++) region[i]='-';
region[9]='\0';
sleep(1);
kill(id_hijo,SIGUSR1);
region[1]='a';
sleep(1);
region[3]='b';
sleep(3);
region[5]='c';
sleep(2);
region[7]='d';
sleep(2);
region[8]='e';
sleep(1);
kill(id_hijo,SIRUSR2);
termina();
}

termina()
{
shmdt(region);
shmctl(shmid,IPC_RMID,NULL);
exit(0);
}

enmarcha()
{
printf("Hijo: (( QuJ ganas tenRa de empezar !!!\n");
return;
}
	--------------------------------------
/* Uso de fork() */
#include <stdio.h>

main()
{
int status, frkpid, chldpd;

printf("Inicio del proceso principal...\n");
if ((frkpid = fork()) == 0 )
  { printf("hijo: mi id de proceso es %d\n",getpid());
   printf("hijo: mi id de proceso padre es %d\n",getppid());
   printf("hijo: mi id de grupo de procesos es %d\n",getpgrp());
   printf("fin del proceso hijo...\n");
   exit(0); }
chldpd=wait(&status);
printf("padre: el id de mi proceso hijo es %d\n", chldpd);
printf("padre: el id de mi proceso es %d\n", getpid());
printf("padre: el id de mi proceso padre es %d\n", getppid());
printf("padre: el id de mi grupo de procesos es %d\n",getpgrp());
printf("fin del proceso padre...\n");
}
	-----------------------------
/* Ejemplo de llamadas al sistema: semget y semop
Ejemlpo de producci\n y consumo. El proceso Padre produce dos elementos y 2 procesos hijos los consumen, si hay suficientes. Una mejora a introducir en este ejemplo es el liquidar el sem<foro al terminar. Este ejemplo es poco correcto, pues se fia del tiempo para una ejecuci\n adecuada. */

#include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>

mainz()
{ int semid;
struct sembuf mibuf;

if ((semid=semget(IPC_PRIVATE,1,0666)) ==-1)
	{ perror("semget"); exit(1); }
switch (fork())
  { case -1: { perror("fork");exit(2); }
    case 0: /* Hijo A */
	sleep(3);
	printf("Hijo A: Quiero 50 unidades \n");
	mibuf.sem_num=0;
	mibuf.sem_op=-50;
	mibuf.sem_flg=0;
	if ( semop(semid,&mibuf,1)==-1)
       { perror("semop"); exit(3); }
	printf("Hijo A: Recibidas las 50 unidades\n");
	sleep(1);
	printf("Hijo A: Ahora qiuero 80 unidades m<s \n");
	mibuf.sem_op=-80;
	if (semop(semid,&mibuf,1)==-1)
       { perror("semop"); exit(4); }
	printf("Hijo A: Recibidas las 80 unidades \n");
	sleep(1);
	printf("Hijo A: Termino por hoy\n");
	exit(0);
	default :
	   switch(fork())
	   {  case -1: { perror("fork"); exit(2); }
	      case 0: /* Hijo B */
		    sleep(3);
		    printf("Hijo B: Quiero 20 unidades \n");
		    mibuf.sem_num=0;
		    mibuf.sem_op=-20;
		    mibuf.sem_flg=0;
		    if ( semop(semid,&mibuf,1)==-1)
			  { perror("semop"); exit(5); }
		    printf("Hijo B: Recibidas las 20 unidades\n");
		    sleep(1);
		    printf("Hijo B: Ahora qiuero 100 unidades m<s \n");
		    mibuf.sem_op=-100;
		    if (semop(semid,&mibuf,1)==-1)
			  { perror("semop"); exit(5); }
		    printf("Hijo B: Recibidas las 100 unidades \n");
		    sleep(1);
		    printf("Hijo B: Termino por hoy\n");
		    exit(0);
	      default :
 		   printf("Padre: Intento producir 100 unidadesn");
		   mibuf.sem_num=0;
		   mibuf.sem_op=100;
		   mibuf.sem_flg=0;
		   if ( semop(semid,&mibuf,1)==-1)
			{ perror("semop"); exit(6); }
		   printf("Padre : Ya he producido 100\n");
		   sleep(5);
		   printf("Padre : Ahora voy a hacer 70 m<s\n");
		   mibuf.sem_op=70;
		   if ( semop(semid,&mibuf,1)==-1)
			{ perror("semop"); exit(7); }
		   printf("Padre : Ya he producido 70\n");
		   sleep(5);
		   printf("Padre : Y por fin voy a hacer 80\n");
		   mibuf.sem_op=80;
		   if ( semop(semid,&mibuf,1)==-1)
			{ perror("semop"); exit(8); }
		   printf("Padre : Ya est<n las 80\n");
		   sleep(5);
		   printf("Padre : Cierro el taller ahora mismo\n");
		   exit(0); } }
}
	------------------------------------
/* Uso de signal() */
#include <stdio.h>  
#include <sys/signal.h>  
  
#define ERROR (-1)  
  
static int caught=0;  
main(argc, argv)  
int argc;  
char *argv[];  
{  
int (*oldint)(), rc=0, catcher();  

if (argc!=1) {  
  fprintf(stderr,"uso: signal1\n");  
  rc=1;  
} else if ((oldint=signal(SIGINT,catcher))==(int (*)()) ERROR){  
     perror(argv[0]);  
     rc=1;  
  } else {  
     for (caught=0;!caught;) 
       printf ("No hay seZal todavia\n");  
  }  
exit (rc);  
}  

int catcher(signo)  
int signo;  
{  
caught=1;  
printf ("Atrapada la seZal ndmero %d\n",signo);  
fflush (stdout);  
}
	------------------------------
/* Uso de la llamada del sistema gettimer() */
#include <stdio.h>
#include <sys/time.h>
main()
{
	long secs;
	int ret;	
	int retc;
	struct timestruc_t *tp;
	tp=(struct timestruc_t *)malloc(sizeof(struct timestruc_t));
	printf("Utilizando la llamada del sistema gettimer... \n");
	ret=gettimer(TIMEOFDAY,tp);
	printf("El tiempo transcurrido es %d\n",tp->tv_sec);
	printf("Suspendiendo la ejecucion por 5 segundos...\n");
	retc=sleep(5);
	printf("Fin de la suspension...\n");
	printf("Se utliza la llamada al sistema time... \n");
	secs=time(0);
	printf("El tiempo transcurrido es %d.\n",secs);
}
	---------------------------------
#include <stdio.h>
#include <string.h>

#define MAXARG 20
#define CIERTO 1
#define FALSO 0
#define PS1 "Orden :"

static void ejecuta (int argc, char *argv[]);
static int getargs (int *argcp, char *argv[], int max);

void main(void)
{  int argc;
char *argv [MAXARG+1];
while (CIERTO) {
  printf("%s",PS1);
  if (!getargs(&argc,argv,MAXARG) || argc==0)
	continue;  /*  Volver a leer una orden */
  ejecuta (argc,argv);   }
  printf("FIN DE EJECUCION \N");   }

static int getargs (int *argcp, char *argv[], int max)
{   static char cmd [100];
char *cmdp;
int i;
if (gets(cmd)==NULL)  return (FALSO);
cmdp=cmd;
for (i=0;i<=max;i++)
  {  if((argv[1]=strtok(cmdp, " \t"))==NULL)  break;
     cmdp=NULL;    }
  if (i>max)   {
       printf("Demasiados argumentos \n");
       return(FALSO);   }
  *argcp=i;
  return(CIERTO);  }

static void ejecuta (int argc, char *argv[])
{  execvp (argv[0], argc);
   printf("No puedo ejecutarlo \n");
}
	-------------------------------
/* Borrado de un fichero temporal cuando el programa es
abortado con un CTRL-C (SeZal SIGINT) */
#define ERROR -1
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>

main()
{ int i, accion();
if (creat("tmp",S_IREAD+S_WRITE)==ERROR)
  { perror("create"); exit(1); }
if (signal(SIGINT,SIG_IGN)!=SIG_IGN)
  signal(SIGINT,accion);
for (i=1; i<100000; i++)
  printf("%d \n",i);
unlink("tmp"); /* por si el bucle termina sin haber seZal */
return (0);
}

int accion()
{
if (unlink("tmp")==ERROR)
   { perror("unlink");
   exit(1); }
else  exit(0);
}
	-----------------------------
/* Ejemplo de llamadas al sistema: kill, pause, signal */
#define ERROR -1
#include <stdio.h>
#include <signal.h>

main()
{ int estatus,pid,accion();
switch(pid=fork())
  { case ERROR: perror("fork");
		exit(1);
  case 0:
	  signal (SIGHUP,accion);
	  printf("Mensaje de HIJO: Espero seZal\n");
	  pause();
	  break;
  default:
	   sleep(2);
	   printf("Mensaje de PADRE: Mando seZal\n");
	   kill(pid,SIGHUP);
	   wait(estatus);
	   printf ("Mensaje de PADRE: HIJO ha terminado\n");  }
return (0);
}

int accion()
{
printf("Mensaje de HIJO: SeZal recibida. Continuo\n");
}




1


